"""
@Author：十
@Time：2024/10/18 15:18
@FileName：EdgeIOT.py
@Description：边缘物联代理API接入工具类
"""

import json
import platform
from datetime import datetime

import paho.mqtt.client as mqtt
import uuid
import cpuinfo
import psutil

# client = None
message_callback = None

# MQTT Broker 配置信息
BROKER = "47.109.106.64"
PORT = 1883
USERNAME = "admin"
PASSWORD = "public"
CLIENT_ID = str(uuid.uuid4().int)[:16].zfill(16)

# 存储 mid 和对应主题的映射关系
subscribe_topics = {}

client = mqtt.Client(client_id=CLIENT_ID, protocol=mqtt.MQTTv5)

partitions = psutil.disk_partitions()
for partition in partitions:
    pass


# 获取操作系统编号
def get_os_code():
    os_full_name = platform.platform()
    os_name = platform.system()
    if os_name == "Linux":
        # 根据操作系统的详细信息进一步判断Linux发行版
        if "Ubuntu" in os_full_name:
            return "1"  # Ubuntu
        elif "Red Hat" in os_full_name or "RedHat" in os_full_name:
            return "2"  # Redhat
        elif "CentOS" in os_full_name:
            return "3"  # CentOS
        elif "PCLinuxOS" in os_full_name:
            return "4"  # PCLinuxOS
        elif "openSUSE" in os_full_name:
            return "5"  # openSUSE
        elif "Mandriva" in os_full_name:
            return "6"  # Mandriva
        elif "Puppy" in os_full_name:
            return "7"  # Puppy Linux
        else:
            return "8"  # 其他Linux发行版
    else:
        return "8"  # 非Linux系统，归为其他


# 获取操作系统相关信息
def os_message():
    os = {
        # 获取操作系统版本
        'os_version': platform.version(),
        # 获取操作系统内核
        'os_kernel': platform.release(),
        # 获取平台软件组件版本
        'platform_version': platform.platform(),
        # 获取操作系统名称
        'os_name': platform.system(),
        # 获取操作系统详细版本信息（用于进一步判断Linux的发行版）
        'os_full_name': platform.platform(),
        # 操作系统代码
        'os_code': get_os_code()
    }
    return os


# 获取IP
def get_default_gateway():
    # 获取网络接口的默认网关
    gateways = psutil.net_if_addrs()
    # 获取默认网关
    gateway = psutil.net_if_stats()
    if gateway:
        for interface, info in gateway.items():
            if info.isup:
                interface_addrs = gateways.get(interface)
                if interface_addrs:
                    for addr in interface_addrs:
                        if addr.family == 2:  # IPv4 地址
                            return addr.address
    return None


# 连接成功的回调函数
def on_connect(client, userdata, flags, reason_code, properties=None):
    if reason_code == 0:
        print("Connected successfully with reason code: ", reason_code)
        return True
    else:
        print("Failed to connect with reason code: ", reason_code)
        return False


def on_message(client, userdata, msg):
    global on_message_callback
    try:
        message_payload = msg.payload.decode()
        print(f"收：: {msg.topic} -> {message_payload} ")

        json_data = json.loads(message_payload)

        # 收到请求站点设备的回复
        if json_data.get("code") == 200:
            if message_callback:
                message_callback(json_data)
            pass
        else:
            return False
    except Exception as e:
        print("Error processing message: ", e)
        return False


# 订阅service/reply
def Subscribe_service():
    mid_service = client.subscribe(f"/v1/{CLIENT_ID}/service/reply", qos=1)[1]
    subscribe_topics[mid_service] = '/service/reply'


def Subscribe_service_edgeID(edgeId):
    client.subscribe(f"/v1/{edgeId}/service/reply", qos=1)


def Subscribe_device():
    res, msg = client.subscribe(f"/v1/{CLIENT_ID}/device/response", qos=1)
    if res == mqtt.MQTT_ERR_SUCCESS:
        return True
    else:
        return False


# 被监测设备标识查询
def Publish_GetLinkedDevice(city, line):
    try:
        topic = f"/v1/{CLIENT_ID}/service/data"
        payload = {
            'param': {
                # "cityName": "国网广元供电公司",  # 所属地市名称(模糊匹配)
                # "lineName": "110kV测试变电站2",  # 所属线路名称或变电站名称(模糊匹配)
                "cityName": city,  # 所属地市名称(模糊匹配)
                "lineName": line,  # 所属线路名称或变电站名称(模糊匹配)
            },
            'mid': CLIENT_ID,
            'timestamp': int(datetime.utcnow().timestamp() * 1000),
            "type": "CMD_GET_LINKEDDEVICE",
        }
        client.publish(topic, json.dumps(payload, ensure_ascii=False), qos=1, retain=False)
        print(f"发： {topic}: {payload}")

    except Exception as e:
        print(f"Error publishing to first topic: {e}")


# 获取edgeId
def Publish_EventLinkUP(pmsCode, lineName):
    try:

        # 获取MAC地址
        mac_address = uuid.UUID(int=uuid.getnode()).hex[-12:]
        os = os_message()

        topic = f"/v1/{CLIENT_ID}/device/request"
        payload = {
            'param': {
                'dev': {
                    'devSN': pmsCode,
                    'devName': lineName,  # 边设备名称（厂家自定义）
                    'mfgInfo': '南京南瑞信息通信科技有限公司',
                    'pmsCode': pmsCode,  # 要填，还要校验
                    'ip': get_default_gateway()  # 本地连接安全网关IP，
                },
                'cpu': {
                    'cpus': cpuinfo.get_cpu_info()['brand_raw'],
                },
                'mem': {
                    'phy': psutil.virtual_memory().total / (1024 ** 3),  # 物理内存，单位是G
                },
                'disk': {
                    'volume': psutil.disk_usage(partition.mountpoint).total / (1024 ** 3),
                },
                'links': [{
                    'name': '4G',
                    'type': '4G',
                    'mac': mac_address,
                }],
                'os': {
                    'distro': os['os_code'],
                    'version': os['os_version'],
                    'kernel': os['os_kernel'],
                    'softVersion': os['platform_version'],
                },

            },
            'mid': CLIENT_ID,
            'timestamp': int(datetime.utcnow().timestamp() * 1000),
            "type": "EVENT_LINKUP",
        }
        client.publish(topic, json.dumps(payload, ensure_ascii=False), qos=1, retain=False)
        print(f"发1： {topic}: {payload}")

    except Exception as e:
        print(f"Error publishing to first topic: {e}")


# 数据上报
def Publish_ReportData(edgeId, devicePMS, test_data):
    # REVIEW
    try:
        print('PMS:', devicePMS)
        print('edgeID:', edgeId)
        topic = f"/v1/{edgeId}/service/data"
        # TODO
        payload = {
            'param': {
                "MonitorData": {
                    json.dumps(test_data)
                },  # T  监测数据(JSON键值对上传，汉字采用UTF-8格式
                # TODO: 检测类型编码，接口实现访问查询？？？？？？
                "DeviceType": "041008",  # T  监测类型编码
                "LinkedDevice": devicePMS,  # T  被监测设备标识
                "MfrsDeviceCode": devicePMS,  # T  厂家装置标识
                "EdgeId": edgeId,  # T  边缘物联代理编码
                "ManufacturerCode": '四川鸿华睿橙智能电气有限公司',  # T  装置厂家(装置厂家)（工商注册全称）
                "FrameSN": 0,  # T  帧序号
                "AcquisitionTime": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),  # T  监测时间
                "Phase": '无',  # T  监测相别
            },
            'mid': CLIENT_ID,
            'timestamp': int(datetime.utcnow().timestamp() * 1000),
            "type": "CMD_REPORTDATA",
        }

        res, msg = client.publish(topic, json.dumps(payload, ensure_ascii=False), qos=1, retain=False)
        print(f"发1： {topic}: {payload}")
        if res == 0:
            return True
    except Exception as e:
        print("数据上报错误：", e)
        return False


# 连接断开的回调函数
def on_disconnect(client, userdata, reason_code, properties=None):
    print("Disconnected with reason code: ", reason_code)


# 连接MQTT服务器
def ConnectMQTT(callback):
    try:
        global client, message_callback
        # client = mqtt.Client(client_id=CLIENT_ID, protocol=mqtt.MQTTv5)
        client.clean_session = True
        KEEP_ALIVE_INTERVAL = 60
        client.keep_alive = KEEP_ALIVE_INTERVAL
    except Exception as e:
        print(f"Error creating MQTT client: {e}")
        client = None

    if client:
        try:
            # 设置账号密码
            deprecated_pw_set = True
            if hasattr(client, 'username_pw_set') and callable(getattr(client, 'username_pw_set')):
                client.username_pw_set(USERNAME, PASSWORD)
                deprecated_pw_set = True
            if not deprecated_pw_set:
                client.tls_set(client)

            # 绑定回调函数
            client.on_connect = on_connect
            client.on_message = on_message
            # client.on_disconnect = on_disconnect

            message_callback = callback

            # 连接到 Broker
            client.connect(BROKER, PORT, keepalive=60)

            # 启动客户端循环
            client.loop_start()

            return True
        except Exception as e:
            print(f"Error during client setup or loop: {e}")
            return False


# 断开连接
def CloseConnection():
    try:
        client.loop_stop()
        client.disconnect()
    except Exception as e:
        print('关闭连接错误：', e)

# if __name__ == "__main__":
#
#     try:
#         client = mqtt.Client(client_id=CLIENT_ID, protocol=mqtt.MQTTv5)
#         client.clean_session = True
#         KEEP_ALIVE_INTERVAL = 60
#         client.keep_alive = KEEP_ALIVE_INTERVAL
#     except Exception as e:
#         print(f"Error creating MQTT client: {e}")
#         client = None
#
#     if client:
#         try:
#             # 设置账号密码
#             deprecated_pw_set = True
#             if hasattr(client, 'username_pw_set') and callable(getattr(client, 'username_pw_set')):
#                 client.username_pw_set(USERNAME, PASSWORD)
#                 deprecated_pw_set = True
#             if not deprecated_pw_set:
#                 client.tls_set(client)
#
#             # 绑定回调函数
#             client.on_connect = on_connect
#             client.on_message = on_message
#             client.on_disconnect = on_disconnect
#
#             # 连接到 Broker
#             client.connect(BROKER, PORT, keepalive=60)
#
#             # 启动客户端循环
#             client.loop_forever()
#         except Exception as e:
#             print(f"Error during client setup or loop: {e}")
